package coalition.formation;

import java.util.List;

import coalition.formation.multiarray.MultiArray;
import coalition.formation.partitions.PartitionDecorator;

public class UtilityAllocation {

	private MultiArray<MultiArray<Float>> altruisms;
	//private MultiArray<Float> powerByCrossSection;
	private MultiArray<Float> populationByCrossSection;
	//private MultiDimensionalExternalityWrapper multiDimensionalExternalityWrapper;
	private float[][] sliceBetas;
	float[] slicePopulations;
	
	public UtilityAllocation(MultiArray<MultiArray<Float>> altruisms,
			MultiArray<Float> populationByCrossSection,
			MultiArray<Float> powerByCrossSection,
			MultiDimensionalExternalityWrapper multiDimensionalExternalityWrapper
	) {
		super();
		this.altruisms = altruisms;
		this.populationByCrossSection = populationByCrossSection;
		//this.powerByCrossSection = powerByCrossSection;
		sliceBetas = multiDimensionalExternalityWrapper.
			convertToOneDimensionalBetas(altruisms, populationByCrossSection);
		slicePopulations = multiDimensionalExternalityWrapper.
			convertToOneDimensionalPopulations(populationByCrossSection);
		
	}
	

	
	
	/*
	 * equal splitting of utilities
	 */
	public float[] distributeUtilitiesToCoalitionMembers(int[] partition, 
			float[] coalitionUtilities,
			List<List<int[]>> partitionByCrossSections){
		float[] result = new float[partition.length];
		List<int[]> coalitionLists = PartitionDecorator.getCoalitionLists(partition);
		//for every coalition in a partition
		int coalitionNumber = 0;
		for(int[] coalition : coalitionLists){
			int coalitionSize = coalition.length;
			float totalUtility = coalitionUtilities[coalitionNumber];
			for(int member: coalition){
				result[member] = totalUtility/coalitionSize;
			}
			coalitionNumber++;
		}		
		return result;
	}	

	/*
	 * Prof. Chin's equation
	 * U_n = U_bar_i * sigma_n/sigma_i + sum{m!=n}[sigma_m/sigma_i*beta_n_m*U_bar_j]
	 * 
	 * takes as array of size equal to the number of coalitions
	 * and returns one of size equal to the number of categories in the
	 * determining attribute
	 * 
	 */	
	
	public float[] distributeUtilitiesToCoalitionMembers2(int[] partition, 
			float[] coalitionUtilities,
			List<List<int[]>> partitionByCrossSections
	){
		float[] result = new float[partition.length];
		List<int[]> coalitionLists = PartitionDecorator.getCoalitionLists(partition);
		
		float[] sigma_i = new float[coalitionUtilities.length];
		int i = 0;	//the index of the source coalition	
		//for every coalition in a partition
		for(int[] sourceCoalition : coalitionLists){
			for(int n: sourceCoalition){	//n is the index of the source cube in i
				sigma_i[i] += slicePopulations[n];
			}
			i++;
		}
		i = 0;
		for(int[] sourceCoalition : coalitionLists){
			float U_bar_i = coalitionUtilities[i];
			int j = 0;
			for(int n: sourceCoalition){
				float U_bar_j = coalitionUtilities[j];
				float sigma_n = slicePopulations[n];
				float sum_m_not_eq_to_m = 0;
				for(int[] targetCoalition : coalitionLists){
					for(int m: targetCoalition){	//m is the index of the target cube
													//in j
						if(i == j && m == n) continue;		//m!=n
						float sigma_m = slicePopulations[m];
						float beta_n_m = sliceBetas[n][m];
						sum_m_not_eq_to_m += sigma_m/sigma_i[i]*beta_n_m*U_bar_j;
					}
					//float U_n = U_bar_i * sigma_n/sigma_i + sum{m!=n}[sigma_m/sigma_i*beta_n_m*U_bar_j];
					result[n] = U_bar_i * sigma_n/sigma_i[i] + sum_m_not_eq_to_m;
					//n++;
				}
				j++;
			}
			i++;
		}		
		return result;
	}
	
}
